﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TdxConnector.Messages;

namespace TdxConnector
{
    public partial class TdxApiDemoForm : Form
    {
        StringBuilder m_MsgString;
        StringBuilder m_DataString;

        public TdxApiDemoForm()
        {
            InitializeComponent();
        }

        private void TdxApiDemoForm_Load(object sender, EventArgs e)
        {
            this.m_DataString = new StringBuilder(1024 * 1024);
            this.m_MsgString = new StringBuilder(256);

            this.comboBox1.SelectedIndex = 0;
            this.comboBox2.SelectedIndex = 0;

            bool bool1 = Tdx_Login(string.Empty, this.m_MsgString);
            if (!bool1)
            {
                MessageBox.Show(this.m_MsgString.ToString());
                this.Close();
            }

            this.Log(this.m_MsgString.ToString());

            Tdx_GetWndText(this.m_DataString);
            string TdxWndText = this.m_DataString.ToString();

            Tdx_GetAccount(this.m_DataString);
            string Account = this.m_DataString.ToString();

            //this.Text = TdxWndText + " " + Account;
        }

        private void TdxApiDemoForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            //注销API
            Tdx_Logout();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            this.button5.Enabled = false;

            //查询
            Tdx_QueryData(this.comboBox2.SelectedIndex, this.m_DataString, this.m_MsgString);
            if (this.comboBox2.SelectedIndex < 3)
            {
                //显示资金信息
                this.textBox2.Text = this.m_DataString.ToString();
            }
            else
            {
                //显示表格信息
                this.DisplayData(this.m_DataString.ToString());
            }
            this.Log(this.m_MsgString.ToString());

            this.button5.Enabled = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //委托
            this.button2.Enabled = false;

            int int1 = Tdx_SendOrder(this.comboBox1.SelectedIndex, this.textBox1.Text, (double)this.numericUpDown2.Value, (int)this.numericUpDown3.Value, this.m_MsgString);
            this.Log(this.m_MsgString.ToString() + "[" + int1.ToString() + "]");

            this.button2.Enabled = true;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //批量委托
            this.button3.Enabled = false;

            for (int i = 0; i < 10; i++)
            {
                int int1 = Tdx_SendOrder(this.comboBox1.SelectedIndex, this.textBox1.Text, (double)this.numericUpDown2.Value, (int)this.numericUpDown3.Value, this.m_MsgString);
                this.Log(this.m_MsgString.ToString() + "[" + int1.ToString() + "]");
            }

            this.Log("批量委托结束。");

            this.button3.Enabled = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //撤委托
            this.button1.Enabled = false;

            bool bool1 = Tdx_CancelOrder((int)this.numericUpDown1.Value, this.m_MsgString);


            this.Log(this.m_MsgString.ToString() + "[" + bool1.ToString() + "]");

            this.button1.Enabled = true;
        }


        //打印日志
        void Log(string Msg)
        {
            this.listView1.Items.Add(new ListViewItem(new string[] { DateTime.Now.ToString("HH:mm:ss"), Msg }));
            this.listView1.EnsureVisible(this.listView1.Items.Count - 1);
        }

        //显示表格数据
        void DisplayData(string Data)
        {
            this.listView2.Items.Clear();
            this.listView2.Columns.Clear();


            if (Data == string.Empty)
            {
                return;
            }



            string[] RowString = Data.Split(new char[] { '\n' });
            string[] ColString = RowString[0].Split(new char[] { '\t' });

            for (int j = 0; j < ColString.Length; j++)
            {
                this.listView2.Columns.Add(ColString[j], 100);
            }


            for (int i = 1; i < RowString.Length; i++)
            {
                ColString = RowString[i].Split(new char[] { '\t' });

                this.listView2.Items.Add(new ListViewItem(ColString));
            }
        }

        //确保tdxapi.dll位于券商下单软件安装目录中。
        //本解决方案生成的TdxApiPlugin.dll输出到券商下单软件安装目录下的plugin文件夹中
        //本解决方案生成的TdxApiDemo.dll输出到券商下单软件安装目录中

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        [return: MarshalAs(UnmanagedType.I1)]
        static extern bool Tdx_Login(string Password, StringBuilder Msg);

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        static extern void Tdx_Logout();

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        static extern void Tdx_GetWndText(StringBuilder Data);

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        static extern void Tdx_GetAccount(StringBuilder Data);

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        static extern void Tdx_QueryData(int Category, StringBuilder Data, StringBuilder Msg);

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        static extern int Tdx_SendOrder(int Category, string Zqdm, double Price, int Quantity, StringBuilder Msg);

        [DllImport("tdxapi.dll", CharSet = CharSet.Ansi)]
        [return: MarshalAs(UnmanagedType.I1)]
        static extern bool Tdx_CancelOrder(int hth, StringBuilder Msg);

        private void orderTimer_Tick(object sender, EventArgs e)
        {
            orderTimer.Enabled = false;

            try
            {
                Process();
            }
            catch 
            {
            }
            finally
            {
                orderTimer.Enabled = true;
            }
        }

        private void Process()
        {
            Message message = null;
            if (MessageQueue.Instance.TryDequeue(out message) && message != null)
            {
                Process(message as CancelOrderMessage);
                Process(message as SendOrderMessage);
                Process(message as GetAssetMessage);
                Process(message as GetOrdersMessage);
                Process(message as GetPositionsMessage);

                message.WaitHandle.Set();
            }
        }
        private void Process(GetPositionsMessage m)
        {
            if (m == null)
                return;

            Tdx_QueryData(3, m_DataString, m_MsgString);

            m.Result = 
                m_DataString.ToString().Split(new char[] { '\n' }).Skip(1)
                .Select(p =>
                    {
                        var splits = p.Trim().Split('\t');
                        if (splits.Length < 11) return null;

                        return new Position()
                        {
                            InstrumentName = splits[0].Trim(),
                            Quantity = int.Parse(splits[1].Trim()),
                            QuantityCanBeSold = int.Parse(splits[2].Trim()),
                            Price = double.Parse(splits[3].Trim()),
                            PnL = double.Parse(splits[4].Trim()),
                            PnlPct = double.Parse(splits[5].Trim()),
                            MarketValue = double.Parse(splits[6].Trim()),
                            MarketPrice = double.Parse(splits[7].Trim()),
                            QuantityBoughtToday = int.Parse(splits[8].Trim()),
                            QuantitySoldToday = int.Parse(splits[9].Trim()),
                            InstrumentCode = splits[10].Trim()
                        };
                    })
                .Where(p => p != null)
                .ToArray();
        }
        private OrderState ParseOrderState(string orderText, string orderDescription)
        {
            Func<string, bool> IsExecuted = t => t == "已成" || t == "已成交" || t == "成交";
            if (orderText.Contains("撤")) return OrderState.Cancelled;
            if (orderText == "买入" && !IsExecuted(orderDescription)) return OrderState.Buying;
            if (orderText == "卖出" && !IsExecuted(orderDescription)) return OrderState.Selling;
            if (orderText == "买入" && IsExecuted(orderDescription)) return OrderState.ExecutedBuy;
            if (orderText == "卖出" && IsExecuted(orderDescription)) return OrderState.ExecutedSell;

            return OrderState.None;
        }
        private OrderType ParseOrderType(string text)
        {
            if (text == "限价") return OrderType.Limit;

            return OrderType.None;
        }

        private void Process(GetOrdersMessage m)
        {
            if (m == null)
                return;

            Tdx_QueryData(4, m_DataString, m_MsgString);

            var orders =
                m_DataString.ToString().Split(new char[] { '\n' }).Skip(1)
                .Select(p =>
                    {
                        var splits = p.Trim().Split('\t');
                        if (splits.Length < 12) return null;

                        return new Order()
                        {
                            InstrumentName = splits[0].Trim(),
                            State = ParseOrderState(splits[1].Trim(), splits[6].Trim()),
                            Price = double.Parse(splits[2].Trim()),
                            Quantity = int.Parse(splits[3].Trim()),
                            ExecutedPrice = double.Parse(splits[4].Trim()),
                            ExecutedQuantity = int.Parse(splits[5].Trim()),
                            //InstrumentName = splits[6].Trim(),
                            OrderTime = DateTime.Parse(splits[7].Trim()),
                            Sequence = int.Parse(splits[8].Trim()),
                            InstrumentCode = splits[9].Trim(),
                            //InstrumentName = splits[10].Trim(),
                            Type = ParseOrderType(splits[11].Trim())
                        };
                    })
                .ToList();

            Tdx_QueryData(5, m_DataString, m_MsgString);

            m_DataString.ToString().Split(new char[] { '\n' }).Skip(1)
                .ToList()
                .ForEach(p =>
                {
                    var splits = p.Trim().Split('\t');
                    if (splits.Length < 11) return;

                    var sequence = int.Parse(splits[8].Trim());
                    var instrumentCode = splits[9].Trim();
                    var executedTime = DateTime.Parse(splits[1].Trim());

                    var order = orders.SingleOrDefault(p1 => p1.Sequence == sequence && ((p1.State & OrderState.Executed) == p1.State));
                    if (order != null)
                    {
                        order.ExecutedTime = executedTime;
                    }
                });

            if (m.ExcludeCancelled)
            {
                foreach (var order in orders.ToArray())
                {
                    orders.Where(p => p != order
                        && p.Sequence == order.Sequence
                        && ((((order.State & OrderState.Executing) == order.State) || p.State == OrderState.Cancelled)
                             || (((p.State & OrderState.Executing) == p.State) || order.State == OrderState.Cancelled)))
                          .ToList()
                          .ForEach(p => orders.Remove(p));

                }
            }

            m.Result = orders.ToArray();
        }
        private void Process(GetAssetMessage m)
        {
            if (m == null)
                return;

            Tdx_QueryData(0, m_DataString, m_MsgString);

            var asset = new Asset();

            m_DataString.ToString().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(p =>
                    {
                        var splits = p.Trim().Trim('\t').Split(':');
                        if (splits.Length < 2) return null;
                        return new Tuple<string, double>(splits[0].Trim(), double.Parse(splits[1].Trim()));
                    })
                .Where(p => p != null)
                .ToList()
                .ForEach(p =>
                {
                    if (p.Item1 == "资产") asset.Total = p.Item2;
                    else if (p.Item1 == "可用") asset.Available = p.Item2;
                    else if (p.Item1 == "盈亏") asset.PnL = p.Item2;
                    else if (p.Item1 == "参考市值") asset.MarketValue = p.Item2;
                });

            m.Result = asset;
        }

        private void Process(SendOrderMessage m)
        {
            if (m == null)
                return;

            try
            {
                m.Result = Tdx_SendOrder(m.category, m.zqdm, m.price, m.quantity, this.m_MsgString);
            }
            catch
            {
            }
        }
        private void Process(CancelOrderMessage m)
        {
            if (m == null)
                return;

            try
            {
                m.Result = Tdx_CancelOrder(m.nth, this.m_MsgString);
            }
            catch
            {
            }
        }
    }
}
